﻿using Sidvall.Caching;
using System.Linq;
using System.Web.Caching;

namespace Sidvall.Web.Caching
{
    public class WebCache : Sidvall.Caching.ICache
    {
        #region Public Members

        #region Add

        public bool Add(CacheItem item, CacheItemPolicy policy)
        {
            if (string.IsNullOrWhiteSpace(item?.Key))
                return false;

            var result = AddCacheItem(item, policy);
            if (result != null)
                return false;
            return true;
        }

        #endregion
        #region AddOrGetExisting

        public CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
        {
            if (string.IsNullOrWhiteSpace(item?.Key))
                return null;

            var value = AddCacheItem(item, policy);
            if (value != null)
            {
                return new CacheItem()
                {
                    Key = item.Key,
                    RegionName = item.RegionName,
                    Value = value,
                };
            }

            return null;
        }

        #endregion
        #region AddOrUpdate

        public void AddOrUpdate(CacheItem item, CacheItemPolicy policy)
        {
            if (string.IsNullOrWhiteSpace(item?.Key))
                return;

            InsertCacheItem(item, policy);
        }

        #endregion
        #region Contains

        public bool Contains(string key, string regionName)
        {
            var value = GetCacheItemValue(key, regionName);
            if (value == null)
                return false;
            return true;
        }

        #endregion
        #region GetCacheItem

        public CacheItem GetCacheItem(string key, string regionName)
        {
            var value = GetCacheItemValue(key, regionName);
            if (value == null)
                return null;
            return new CacheItem()
            {
                 Key = key,
                 RegionName = regionName,
                 Value = value,
            };
        }

        #endregion
        #region GetCacheItemValue

        public object GetCacheItemValue(string key, string regionName)
        {
            return this.Cache.Get(key);
        }

        #endregion
        #region GetCount

        public long GetCount(string regionName)
        {
            return this.Cache.Count;
        }

        #endregion
        #region Remove

        public object Remove(string key, string regionName)
        {
            return this.Cache.Remove(key);
        }

        #endregion

        #region ToString

        public override string ToString()
        {
            return "Cache - Web";
        }

        #endregion

        #endregion
        #region Private Members

        private Cache Cache { get; set; }

        #region AddCacheItem

        private object AddCacheItem(CacheItem item, CacheItemPolicy policy)
        {
            return this.Cache.Add(item.Key, item.Value, null,
                GetAbsoluteExpiration(policy),
                GetSlidingExpiration(policy),
                GetPriority(policy),
                null);
        }

        #endregion
        #region InsertCacheItem

        private void InsertCacheItem(CacheItem item, CacheItemPolicy policy)
        {
            this.Cache.Insert(item.Key, item.Value, null,
                GetAbsoluteExpiration(policy),
                GetSlidingExpiration(policy),
                GetPriority(policy),
                null);
        }

        #endregion
        #region GetAbsoluteExpiration

        private static System.DateTime GetAbsoluteExpiration(CacheItemPolicy policy)
        {
            if (policy?.AbsoluteExpiration == null)
                return System.Web.Caching.Cache.NoAbsoluteExpiration;
            return policy.AbsoluteExpiration.Value.UtcDateTime;
        }

        #endregion
        #region GetPriority

        private static System.Web.Caching.CacheItemPriority GetPriority(CacheItemPolicy policy)
        {
            switch (policy.Priority)
            {
                case Sidvall.Caching.CacheItemPriority.Low:
                    return System.Web.Caching.CacheItemPriority.Low;
                case Sidvall.Caching.CacheItemPriority.BelowNormal:
                    return System.Web.Caching.CacheItemPriority.BelowNormal;
                case Sidvall.Caching.CacheItemPriority.Normal:
                    return System.Web.Caching.CacheItemPriority.Normal;
                case Sidvall.Caching.CacheItemPriority.AboveNormal:
                    return System.Web.Caching.CacheItemPriority.AboveNormal;
                case Sidvall.Caching.CacheItemPriority.High:
                    return System.Web.Caching.CacheItemPriority.High;
                case Sidvall.Caching.CacheItemPriority.NotRemovable:
                    return System.Web.Caching.CacheItemPriority.NotRemovable;
                default:
                    return System.Web.Caching.CacheItemPriority.Default;
            }
        }

        #endregion
        #region GetSlidingExpiration

        private static System.TimeSpan GetSlidingExpiration(CacheItemPolicy policy)
        {
            if (policy?.SlidingExpiration == null)
                return System.Web.Caching.Cache.NoSlidingExpiration;
            if (policy?.AbsoluteExpiration != null)
                return System.Web.Caching.Cache.NoSlidingExpiration;
            return policy.SlidingExpiration.Value;
        }

        #endregion

        #endregion
        #region Constructors

        public WebCache()
        {
            this.Cache = new Cache();
        }

        #endregion
    }
}
